スポットインスタンスのターミネート通知を試してみた
はじめに
AWSチームのすずきです。
AWSが提供するEC2のスポットインスタンス。 需要と供給に応じ価格が変動するEC2インスタンスを入札して利用します。
スポットインスタンスの価格が入札価格を超えた場合、強制停止されるリスクを伴いますが、 オンデマンドインスタンスと比較し、大幅に安価な費用(平均86%の割引)でEC2環境を利用する事が可能です。
先日のAWSのアップデートにより、スポットインスタンスが強制停止する2分前に検出する事が可能となりました。
【AWS発表】EC2スポットインスタンスのターミネート通知機能
今回、ターミネート通知がどの様に行われるか、起動したスポットインスタンスを入札金額不足により強制停止させ、下記情報の遷移について確認を実施しましたので、紹介させていただきます。
- スポットインスタンスのメタ情報
- スポットインスタンスのリクエストステータス
環境
利用OS
- AMI:amzn-ami-hvm-2014.09.2.x86_64-ebs (ami-dfc39aef:us-west-2)
- インスタンス:c3.large
- リージョン:米国西海岸(us-west-2c)
- スポット入札価格(1h):0.0176ドル(1h) ※オンデマンド定価は0.105ドル
確認対象
メタデータ情報(termination-time)
wget -q -O - http://169.254.169.254/latest/meta-data/spot/termination-time
スポットリクエストのステータス
aws ec2 describe-spot-instance-requests | jq .SpotInstanceRequests[].Status
測定方法
シェルをループ、5秒毎に測定を実施
while : do wget -q -O - http://169.254.169.254/latest/meta-data/spot/termination-time aws ec2 describe-spot-instance-requests | jq .SpotInstanceRequests[].Status sleep 5 done
結果
10:04:50 UTC(継続稼働中)
メタデータ
<?xml version="1.0" encoding="iso-8859-1"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <title>404 - Not Found</title> </head> <body> <h1>404 - Not Found</h1> </body> </html>
※強制停止対象外の場合、「http://169.254.169.254/latest/meta-data/spot/termination-time」のURIは存在せず、メタデータを取得するHTTPリクエストは404が戻ります。
スポットリクエスト
{ "UpdateTime": "2015-02-16T09:46:36.000Z", "Code": "fulfilled", "Message": "Your Spot request is fulfilled." }
10:04:56 UTC(ターミネート通知検出)
メタデータ
2015-02-16T10:06:53Z
スポットリクエストステータス
{ "UpdateTime": "2015-02-16T10:04:53.000Z", "Code": "marked-for-termination", "Message": "Your Spot Instance is marked for termination because your Spot request price of 0.0175 is lower than the minimum required fulfillment price of 0.0176 in us-west-2c." }
10:07:07 UTC(ターミネート執行直前)
メタデータ
2015-02-16T10:06:53Z
スポットリクエストステータス
{ "UpdateTime": "2015-02-16T10:04:53.000Z", "Code": "marked-for-termination", "Message": "Your Spot Instance is marked for termination because your Spot request price of 0.0175 is lower than the minimum required fulfillment price of 0.0176 in us-west-2c." }
110:07:13 UTC(ターミネート執行)
The system is going down for power off NOW! Connection to 52.xx.xx.xx closed by remote host. Connection to 52.xx.xx.xx closed.
スポットリクエストステータス
{ "UpdateTime": "2015-02-16T10:07:19.000Z", "Code": "instance-terminated-by-price", "Message": "Your Spot Instance was terminated because your Spot request price was lower than required fulfillment price." }
考察
スポット価格の高騰によりEC2のスポットインスタンスが停止した場合、 ELB配下で利用していた場合でもヘルスチェックにより負荷分散対象から除外されるまで、 一時的ですが応答エラーが発生する可能性がありました。
今回のAWSのアップデートにより2分間の猶予時間が得られた事により、 停止対象となったスポットインスタンスのEC2、所属するELBから自身の取外しを実施しサービス影響を回避する処理、 以下の様なシェルスクリプトで簡単に実装する事が可能となりました。
#!/bin/bash export AWS_DEFAULT_REGION=`curl -s http://169.254.169.254/latest/meta-data/local-hostname | cut -d '.' -f2` f_check_metadata_termination() { STR=`wget -q -O - http://169.254.169.254/latest/meta-data/spot/termination-time` #Termination通知判定 if [ $? -eq 0 ]; then if [[ "${STR}" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$ ]]; then f_elb_deregister_ec2 fi fi } f_elb_deregister_ec2() { INSTANCEID=`curl -s http://169.254.169.254/latest/meta-data/instance-id`` aws elb describe-load-balancers \ | jq -r ".LoadBalancerDescriptions[] | select (.Instances[].InstanceId == \"${INSTANCEID}\" )| .LoadBalancerName" \ | xargs -n1 -I{} aws elb deregister-instances-from-load-balancer --load-balancer-names {} --instances ${INSTANCEID} } for i in {1..5} do f_check_metadata_termination sleep 10 done
※AWS権限、EC2ロールで付与済を想定。
また、オートスケール設定との連携強化への応用。 スポット価格が高騰しスポットインスタンスの維持が困難となった場合、インスタンスの稼働台数をオンデマンドインスタンスで確保する実装についても効果的と考えられます。
まとめ
EC2のスポットインスタンス、スケールメリットが活きるAWSならではのサービスです。
リスクが許容される箇所での利用や、リスクを工夫で回避する事で、大きな効果が得られる可能性があります。 クラウドを活用したシステムを実現するにあたり、手段の一つとして是非ご検討頂ければと思います。